<template>
  <div class="form-designer">
    <div v-if="header" class="widget-container-header">
      <design-toolbar :toolbar="toolbar">
        <template #toolbar-left>

          <slot name="toolbar-left">
            <el-dropdown v-if="undoRedo">
              <el-button
                  link
                  type="primary"
                  size="default"
                  icon="el-icon-edit">操作
                <el-icon class="el-icon--right">
                  <arrow-down/>
                </el-icon>
              </el-button>

              <template #dropdown>
                <el-dropdown-menu>
                  <el-dropdown-item
                      divided
                      v-if="undoRedo" :disabled="historySteps.index === 0"
                      @click.native="widgetForm = handleUndo()">撤销
                  </el-dropdown-item>
                  <el-dropdown-item
                      divided
                      v-if="undoRedo" :disabled="historySteps.index === historySteps.steps.length - 1"
                      @click.native="widgetForm = handleRedo()">重做
                  </el-dropdown-item>
                  <el-dropdown-item
                      divided
                      v-if="toolbar.includes('clear')"
                      icon="el-icon-delete"
                      @click.native=" handleClear()"><span>清空</span>
                  </el-dropdown-item>
                  <el-dropdown-item divided v-if="toolbar.includes('import')"
                                    @click.native="$refs.formImportJson.importJson()">导入JSON
                  </el-dropdown-item>

                </el-dropdown-menu>
              </template>
            </el-dropdown>
            <el-dropdown>
              <el-button
                  link
                  type="primary"
                  size="default"
                  icon="el-icon-search">预览
                <el-icon class="el-icon--right">
                  <arrow-down/>
                </el-icon>
              </el-button>
              <template #dropdown>
                <el-dropdown-menu>
                  <el-dropdown-item @click.native="$refs.formPreview.show(widgetForm)">预览表单
                  </el-dropdown-item>
                  <el-dropdown-item @click.native="$refs.formPreviewTable.show(widgetForm)">预览表格
                  </el-dropdown-item>
                  <el-dropdown-item @click.native="$refs.formPreviewJson.show(widgetForm)">预览json
                  </el-dropdown-item>
                </el-dropdown-menu>
              </template>
            </el-dropdown>
            <el-dropdown>
              <el-button
                  link
                  type="primary"
                  size="default"
                  icon="el-icon-search">保存
                <el-icon class="el-icon--right">
                  <arrow-down/>
                </el-icon>
              </el-button>
              <template #dropdown>
                <el-dropdown-menu>
                  <el-dropdown-item v-if="toolbar.includes('generate')"
                                    @click.native="$refs.formPreviewJson.show(widgetForm)">
                    生成JSON
                  </el-dropdown-item>
                  <el-dropdown-item v-if="toolbar.includes('save')"
                                    icon="el-icon-edit-outline"
                                    @click.native="saveOption()">保存
                  </el-dropdown-item>
                  <slot name="save-dropdown-item"></slot>
                </el-dropdown-menu>
              </template>
            </el-dropdown>
          </slot>
        </template>
        <template #toolbar-center>
          <slot name="toolbar-center">
          </slot>
        </template>
        <template #toolbar-right>
          <slot name="toolbar-right"></slot>
          <el-button v-if="toolbar.includes('close')"
                     link
                     type="primary"
                     size="default"
                     @click="$emit('close')"
                     icon="el-icon-close">关闭
          </el-button>
        </template>
      </design-toolbar>
    </div>
    <split-panes class="default-theme" style="height: calc(100% - 65px);margin-top: 5px" @resized="panesResized">
      <pane size="20%">
        <div class="fields-list">
          <div v-for="(field, index) in fields" :key="index">
            <template v-if="field.list.find(f => includeFields.includes(f.type))">
              <div class="field-title">{{ field.title }}</div>
              <draggable tag="ul" :list="field.list" :group="{ name: 'form', pull: 'clone', put: false }"
                         ghost-class="ghost" :sort="false">
                <template #item="{element,index}">
                  <li class="field-label"
                      v-if="includeFields.includes(element.type)"
                      :key="index">
                    <a @click="handleFieldClick(element)">
                      <i class="icon iconfont"
                         :class="element.icon"></i>
                      <span>{{ element.title || element.label }}</span>
                    </a>
                  </li>
                </template>
              </draggable>
            </template>
          </div>
        </div>
      </pane>
      <pane>
        <div :key="designMainKey"
             class="padding"
             :style="{background: widgetForm.column.length === 0 ? `url(${widgetEmpty}) no-repeat 50%`: ''}"
             style="height: 100%;">
          <widget-form ref="widgetForm"
                       :data="widgetForm"
                       v-model:select="widgetFormSelect"
                       :sql-type-mapper="sqlTypeMapper"
                       @change="handleHistoryChange(widgetForm)"></widget-form>
        </div>
      </pane>
      <pane size="20%">
        <el-tabs class="flex_header" v-model="configTab"
                 stretch>
          <el-tab-pane label="字段属性"
                       name="widget"
                       style="padding: 0 10px;">
            <widget-config :data="widgetFormSelect"></widget-config>
          </el-tab-pane>
          <el-tab-pane label="表单属性"
                       name="form"
                       lazy
                       style="padding: 0 10px;">
            <form-config :data="widgetForm"></form-config>
          </el-tab-pane>
        </el-tabs>
      </pane>
    </split-panes>

    <form-preview-json ref="formPreviewJson"></form-preview-json>
    <form-preview ref="formPreview"></form-preview>
    <form-import-json ref="formImportJson" @submit="formImportJsonSuccess"></form-import-json>
    <form-preview-table ref="formPreviewTable"></form-preview-table>
    <edit-form-code-drawer ref="editFormCodeDrawer "></edit-form-code-drawer>

  </div>
</template>

<script>
import fields from './fieldsConfig.js'
import widgetEmpty from './assets/widget-empty.png'
import history from './mixins/history'

import Draggable from 'vuedraggable'

import WidgetForm from './WidgetForm.vue'
import FormConfig from './FormConfig.vue'
import WidgetConfig from './WidgetConfig.vue'
import DesignToolbar from "./designToolbar.vue";
import FormPreview from "./formPreview.vue";
import FormImportJson from "./formImportJson.vue";
import FormPreviewTable from "./formPreviewTable.vue";

import key from 'keymaster'
import startMySqlMapper from "./startMySqlMapper";
import startColMapperTools from "./startColMapperTools";
import {Sort} from "@element-plus/icons-vue";
import designTools from "components/form-design/utils/designTools";
import FormPreviewJson from "components/form-design/formPreviewJson.vue";
import EditFormCodeDrawer from "components/form-design/editFormCodeDrawer.vue";
import SplitPanes from "components/splitpanes/SplitPanes.vue";
import Pane from "components/splitpanes/pane.vue";


export default {
  name: "FormDesign",
  components: {
    Pane,
    SplitPanes,

    EditFormCodeDrawer,
    FormPreviewJson,
    Sort,
    FormPreviewTable,
    FormImportJson,
    FormPreview,
    DesignToolbar,
    Draggable,
    WidgetForm,
    FormConfig,
    WidgetConfig
  },
  mixins: [history],
  props: {
    header: {
      type: Boolean,
      default: true,
    },
    options: {
      type: [Object, String],
      default: () => {
        return {
          column: []
        }
      },
      dataStorageType: {
        type: String,
        default: ""
      }
    },
    storage: {
      type: Boolean,
      default: false
    },
    asideLeftWidth: {
      type: [String, Number],
      default: '270px'
    },
    asideRightWidth: {
      type: [String, Number],
      default: '380px'
    },
    showGithubStar: {
      type: Boolean,
      default: true
    },
    toolbar: {
      type: Array,
      default: () => {
        return ['import', 'generate', 'preview', 'clear', "save", 'close']
      }
    },
    undoRedo: {
      type: Boolean,
      default: true
    },
    includeFields: {
      type: Array,
      default: () => {
        const arr = []
        fields.forEach(f => {
          f.list.forEach(c => {
            arr.push(c.type)
          })
        })
        return arr
      }
    },
    customFields: {
      type: Array,
    },
    sqlTypeMapper: {
      type: Object,
      default: () => {
        return startMySqlMapper
      }
    }
  },
  provide() {
    return {
      getSqlTypeMapper: () => {
        return this.sqlTypeMapper
      },
    }
  },
  watch: {
    options: {
      handler(val) {
        let options = val
        if (typeof options == 'string') {
          try {
            options = eval('(' + options + ')')
          } catch (e) {
            console.error('非法配置')
            options = {column: []}
          }
        }
        options = startColMapperTools.formOptionToSQL(options, this.sqlTypeMapper)
        this.transAvueOptionsToFormDesigner(options).then(res => {
          this.widgetForm = {...this.widgetForm, ...res}
        })
      },
      deep: true
    }
  },
  computed: {
    leftWidth() {
      if (typeof this.asideLeftWidth == 'string') {
        return this.asideLeftWidth
      } else {
        return `${this.asideLeftWidth}px`
      }
    },
    rightWidth() {
      if (typeof this.asideRightWidth == 'string') {
        return this.asideRightWidth
      } else {
        return `${this.asideRightWidth}px`
      }
    }
  },
  data() {
    return {
      widgetEmpty,
      fields,
      widgetForm: {
        column: [],
        labelPosition: 'left',
        labelSuffix: '：',
        labelWidth: 120,
        gutter: 0,
        menuBtn: true,
        submitBtn: true,
        submitText: '提交',
        emptyBtn: true,
        emptyText: '清空',
        menuPosition: 'center'
      },
      configTab: 'widget',
      widgetFormSelect: {},
      widgetModels: {},
      history: {
        index: 0, // 当前下标
        maxStep: 20, // 最大记录步数
        steps: [], // 历史步数
      },
      designMainKey: Math.random(),
    }
  },
  mounted() {
    this.handleLoadStorage()
    this.handleLoadCss()
    key.unbind("ctrl+s", "all")
    key('ctrl+s', () => {
      this.saveOption()
      return false;
    });
  },

  methods: {
    panesResized(data) {

    },
    // 组件初始化时加载本地存储中的options(需开启storage),若不存在则读取用户配置的options
    async handleLoadStorage() {
      let options = this.options
      if (typeof options == 'string') {
        try {
          options = eval('(' + options + ')')
        } catch (e) {
          console.error('非法配置')
          options = {column: []}
        }
      }
      if (!options.column) options.column = []
      this.widgetForm = this.initHistory({
        index: 0,
        maxStep: 20,
        steps: [await this.transAvueOptionsToFormDesigner({...this.widgetForm, ...options})],
        storage: this.storage
      })

      if (this.undoRedo) {
        window.addEventListener('keydown', (evt) => {
          // 监听 cmd + z / ctrl + z 撤销
          if ((evt.metaKey && !evt.shiftKey && evt.keyCode === 90) || (evt.ctrlKey && !evt.shiftKey && evt.keyCode == 90)) {
            this.widgetForm = this.handleUndo()
          }
          // 监听 cmd + shift + z / ctrl + shift + z / ctrl + y 重做
          if ((evt.metaKey && evt.shiftKey && evt.keyCode == 90) || (evt.ctrlKey && evt.shiftKey && evt.keyCode == 90) || (evt.ctrlKey && evt.keyCode == 89)) {
            this.widgetForm = this.handleRedo()
          }
        }, false)
      }

    },
    // 加载icon
    handleLoadCss() {
      const head = document.getElementsByTagName('head')[0]
      const script = document.createElement('link')
      script.rel = 'stylesheet'
      script.type = 'text/css'
      script.href = 'https://at.alicdn.com/t/font_1254447_zc9iezc230c.css'
      head.appendChild(script)
    },


    // 左侧字段点击
    handleFieldClick(item) {
      const activeIndex = this.widgetForm.column.findIndex(c => c.prop === this.widgetFormSelect.prop) + 1
      let newIndex = 0
      if (activeIndex === -1) {
        this.widgetForm.column.push(item)
        newIndex = this.widgetForm.column.length - 1
      } else {
        this.widgetForm.column.splice(activeIndex, 0, item)
        newIndex = activeIndex
      }
      this.$refs.widgetForm.handleWidgetAdd({newIndex})
    },
    formImportJsonSuccess(data, done) {
      this.widgetForm = data
      this.handleHistoryChange(data)
      done()
    },

    // 清空
    handleClear() {
      if (!this.widgetForm || !this.widgetForm.column || this.widgetForm.column.length < 1) {
        this.$message.error("没有需要清空的内容")
        return
      }
      this.$confirm('确定要清空吗？', '警告', {
        type: 'warning'
      }).then(() => {
        let temp = {};
        temp.column = []
        this.widgetForm = temp
        this.widgetModels = {};
        this.widgetFormSelect = {};
        this.handleHistoryChange(this.widgetForm)
      }).catch(() => {
      })
    },
    saveOption() {
      this.transformToAvueOptions(this.widgetForm).then(data => {
        data = startColMapperTools.formOptionToSQL(data, this.sqlTypeMapper)
        // console.log("data", data)
        this.$emit("submit", data)
      })
    },
    getFormOption() {
      return this.transformToAvueOptions(this.widgetForm);
    },
    // 表单设计器配置项 转化为 Avue配置项
    transformToAvueOptions(obj) {
      return new Promise((resolve, reject) => {
        try {
          let data = designTools.designOptionToAvueOption(obj)
          resolve(data)
        } catch (e) {
          reject(e)
        }
      })
    },

    transAvueOptionsToFormDesigner(obj) {
      return new Promise((resolve, reject) => {
        try {
          let data = designTools.avueOptionToDesignOption(obj)
          resolve(data)
        } catch (e) {
          reject(e)
        }
      })
    },
    preview(type) {
      if (!type) {
        type = "table"
      }
      type = type.toLowerCase();
      switch (type) {
        case "table":
          this.$refs.formPreviewTable.show(this.widgetForm)
          break;
        case "form":
          this.$refs.formPreview.show(this.widgetForm)
          break;
        case "json":
          this.$refs.formPreviewJson.show(this.widgetForm)
          break;
      }

    }

  },
  beforeUnmount() {
    key.unbind("ctrl+s", "all")
  },
}
</script>

<style lang="scss">
@use './styles/index';
</style>
